package com.sqfw.project.taskForXml.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sqfw.common.utils.DateUtils;
import com.sqfw.project.taskForXml.domain.FtpUploadFileLog;
import com.sqfw.project.taskForXml.mapper.FtpUploadFileLogMapper;
import com.sqfw.project.taskForXml.mapper.TaskForXmlMapper;
import com.sqfw.project.taskForXml.service.TaskForXmlService;
import com.sqfw.project.utils.FTP2Tools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 查询数据 生成xml文件  上传到ftp上 Service层
 *
 * @author tangxt
 * @date 2024-03-18
 */
@Slf4j
@Service
public class TaskForXmlServiceImpl implements TaskForXmlService {

    @Autowired
    private TaskForXmlMapper taskForXmlMapper;

    @Autowired
    private FtpUploadFileLogMapper ftpUploadFileLogMapper;

    private static final String FILE_TYPE_XML = "XML";

    private static final String FILE_PATH = "/file/";
    /** XML文件数据编码GB2312 */
    private static final String ENCODING_GB2313 = "GB2312";
    /** XML文件数据编码UTF-8 */
    private static final String ENCODING_UTF8 = "UTF-8";

    SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");

    /**
     * 1.第一个定时任务
     * 把昨天的录音表（ZJ_RECORD_INFO表）数据，转换成xml文件，ftp上传给大数据中心
     */
    @Override
    public void taskForXmlZjRecordInfo() {
        FtpUploadFileLog ftpUploadFileLog = new FtpUploadFileLog();
        try {
            List<Map<String, Object>> list = taskForXmlMapper.queryZjRecordInfoList();
            if (!CollectionUtils.isEmpty(list)) {
                String dir = this.sf.format(new Date());
                String fileName = "962200_THJLXXYS_" + dir + ".xml";
                String pathname = System.getProperty("user.dir") + FILE_PATH + fileName;
                File file = new File(pathname);
                // 创建xml文件
                boolean isCreateFile = this.listToXml(list, file);
                ftpUploadFileLog.setFileName(fileName);
                ftpUploadFileLog.setFileType(FILE_TYPE_XML);
                ftpUploadFileLog.setFileSize(String.valueOf(file.length()));
                // 创建文件成功,上传文件
                if (isCreateFile) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    // 上传文件
                    this.uploadFile(fileInputStream, fileName, null, ftpUploadFileLog);
                }
                ftpUploadFileLog.setIsCreateFile(isCreateFile);
                ftpUploadFileLog.setFileOriginPath(pathname);
            } else {
                log.info("queryZjRecordInfoList:未查询到数据");
                ftpUploadFileLog.setUploadErrorMsg("queryZjRecordInfoList:未查询到数据");
            }
            // ftp上传记录入库，记录是否上传成功，如果不成功就定时任务上传
            this.addFtpUploadFileLog(ftpUploadFileLog);
        } catch (Exception e) {
            log.info("taskForXmlZjRecordInfo-ftp上传文件失败：{}", e.getMessage());
            ftpUploadFileLog.setUploadErrorMsg(e.getMessage().substring(0, 3000));
            this.addFtpUploadFileLog(ftpUploadFileLog);
        }
    }

    /**
     * 2.第二个定时任务
     * 把昨天的工单回访数据（wp_visit_info表），转换成xml文件，ftp上传给大数据中心
     */
    @Override
    public void taskForXmlWpVisitInfo() {
        FtpUploadFileLog ftpUploadFileLog = new FtpUploadFileLog();
        try {
            List<Map<String, Object>> list = this.taskForXmlMapper.queryWpVisitInfoList();
            if (!CollectionUtils.isEmpty(list)) {
                String dir = this.sf.format(new Date());
                String fileName = "962200_HFXXYS_" + dir + ".xml";
                String pathname = System.getProperty("user.dir") + FILE_PATH + fileName;
                File file = new File(pathname);
                // 创建xml文件
                boolean isCreateFile = this.listToXml(list, file);
                ftpUploadFileLog.setFileName(fileName);
                ftpUploadFileLog.setFileType(FILE_TYPE_XML);
                ftpUploadFileLog.setFileSize(String.valueOf(file.length()));
                // 创建文件成功,上传文件
                if (isCreateFile) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    this.uploadFile(fileInputStream, fileName, null, ftpUploadFileLog);
                }
                ftpUploadFileLog.setIsCreateFile(isCreateFile);
                ftpUploadFileLog.setFileOriginPath(pathname);
            } else {
                log.info("queryWpVisitInfoList:未查询到数据");
                ftpUploadFileLog.setUploadErrorMsg("queryWpVisitInfoList:未查询到数据");
            }
            // ftp上传记录入库，记录是否上传成功，如果不成功就定时任务上传
            this.addFtpUploadFileLog(ftpUploadFileLog);
        } catch (Exception e) {
            log.info("taskForXmlWpVisitInfo-ftp上传文件失败：{}", e.getMessage());
            ftpUploadFileLog.setUploadErrorMsg(e.getMessage().substring(0, 3000));
            this.addFtpUploadFileLog(ftpUploadFileLog);
        }
    }

    /**
     * 3.第三个定时任务
     * 把昨天的工单轨迹数据（wp_handle_log表，last_state = '承办单位处理'），
     * 转换成xml文件，ftp上传给大数据中心
     */
    @Override
    public void taskForXmlWpHandleLog() {
        FtpUploadFileLog ftpUploadFileLog = new FtpUploadFileLog();
        try {
            List<Map<String, Object>> list = this.taskForXmlMapper.queryWpHandleLogList();
            if (!CollectionUtils.isEmpty(list)) {
                String dir = this.sf.format(new Date());
                String fileName = "962200_BJXXYS_" + dir + ".xml";
                String pathname = System.getProperty("user.dir") + FILE_PATH + fileName;
                File file = new File(pathname);
                // 创建xml文件
                boolean isCreateFile = this.listToXml(list, file);
                ftpUploadFileLog.setFileName(fileName);
                ftpUploadFileLog.setFileType(FILE_TYPE_XML);
                ftpUploadFileLog.setFileSize(String.valueOf(file.length()));
                // 创建文件成功,上传文件
                if (isCreateFile) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    this.uploadFile(fileInputStream, fileName, null, ftpUploadFileLog);
                }
                ftpUploadFileLog.setIsCreateFile(isCreateFile);
                ftpUploadFileLog.setFileOriginPath(pathname);
            } else {
                log.info("queryWpHandleLogList:未查询到数据");
                ftpUploadFileLog.setUploadErrorMsg("queryWpHandleLogList:未查询到数据");
            }
            // ftp上传记录入库，记录是否上传成功，如果不成功就定时任务上传
            this.addFtpUploadFileLog(ftpUploadFileLog);
        } catch (Exception e) {
            log.info("taskForXmlWpHandleLog-ftp上传文件失败：{}", e.getMessage());
            ftpUploadFileLog.setUploadErrorMsg(e.getMessage().substring(0, 3000));
            this.addFtpUploadFileLog(ftpUploadFileLog);
        }
    }

    /**
     * 4.第四个定时任务
     * 把昨天的工单回访数据（wp_visit_info表，和上面方法返回的字段不一样），
     * 转换成xml文件，ftp上传给大数据中心
     */
    @Override
    public void taskForXmlWpVisitInfo2() {
        FtpUploadFileLog ftpUploadFileLog = new FtpUploadFileLog();
        try {
            List<Map<String, Object>> list = this.taskForXmlMapper.queryWpVisitInfoList2();
            if (!CollectionUtils.isEmpty(list)) {
                String dir = this.sf.format(new Date());
                String fileName = "962200_MYDCPXXYS_" + dir + ".xml";
                String pathname = System.getProperty("user.dir") + FILE_PATH + fileName;
                File file = new File(pathname);
                // 创建xml文件
                boolean isCreateFile = this.listToXml(list, file);
                ftpUploadFileLog.setFileName(fileName);
                ftpUploadFileLog.setFileType(FILE_TYPE_XML);
                ftpUploadFileLog.setFileSize(String.valueOf(file.length()));
                // 创建文件成功,上传文件
                if (isCreateFile) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    this.uploadFile(fileInputStream, fileName, null, ftpUploadFileLog);
                }
                ftpUploadFileLog.setIsCreateFile(isCreateFile);
                ftpUploadFileLog.setFileOriginPath(pathname);
            } else {
                log.info("queryWpVisitInfoList2:未查询到数据");
                ftpUploadFileLog.setUploadErrorMsg("queryWpVisitInfoList2:未查询到数据");
            }
            // ftp上传记录入库，记录是否上传成功，如果不成功就定时任务上传
            this.addFtpUploadFileLog(ftpUploadFileLog);
        } catch (Exception e) {
            log.info("taskForXmlWpVisitInfo2-ftp上传文件失败：{}", e.getMessage());
            ftpUploadFileLog.setUploadErrorMsg(e.getMessage().substring(0, 3000));
            this.addFtpUploadFileLog(ftpUploadFileLog);
        }
    }

    /**
     * 5.第五个定时任务
     * 把昨天的工单数据（wp_info表，有筛选条件），
     * 转换成xml文件，ftp上传给大数据中心
     */
    @Override
    public void taskForXmlWpInfo() {
        FtpUploadFileLog ftpUploadFileLog = new FtpUploadFileLog();
        try {
            List<Map<String, Object>> list = this.taskForXmlMapper.queryWpInfoList();
            if (!CollectionUtils.isEmpty(list)) {
                String dir = this.sf.format(new Date());
                String fileName = "962200_GDXXYS_" + dir + ".xml";
                String pathname = System.getProperty("user.dir") + FILE_PATH + fileName;
                File file = new File(pathname);
                // 创建xml文件
                boolean isCreateFile = this.listToXml(list, file);
                ftpUploadFileLog.setFileName(fileName);
                ftpUploadFileLog.setFileType(FILE_TYPE_XML);
                ftpUploadFileLog.setFileSize(String.valueOf(file.length()));
                // 创建文件成功,上传文件
                if (isCreateFile) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    this.uploadFile(fileInputStream, fileName, null, ftpUploadFileLog);
                }
                ftpUploadFileLog.setIsCreateFile(isCreateFile);
                ftpUploadFileLog.setFileOriginPath(pathname);
            } else {
                log.info("queryWpInfoList:未查询到数据");
                ftpUploadFileLog.setUploadErrorMsg("queryWpInfoList:未查询到数据");
            }
            // ftp上传记录入库，记录是否上传成功，如果不成功就定时任务上传
            this.addFtpUploadFileLog(ftpUploadFileLog);
        } catch (Exception e) {
            log.info("taskForXmlWpInfo-ftp上传文件失败：{}", e.getMessage());
            ftpUploadFileLog.setUploadErrorMsg(e.getMessage().substring(0, 3000));
            this.addFtpUploadFileLog(ftpUploadFileLog);
        }
    }

    /**
     * 6.第六个定时任务
     * 把昨天的录音表（ZJ_RECORD_INFO表）数据（和上面方法返回的字段不一样），
     * 转换成xml文件，ftp上传给大数据中心
     */
    @Override
    public void taskForXmlZjRecordInfo2() {
        FtpUploadFileLog ftpUploadFileLog = new FtpUploadFileLog();
        try {
            List<Map<String, Object>> list = this.taskForXmlMapper.queryZjRecordInfoList2();
            if (!CollectionUtils.isEmpty(list)) {
                String dir = this.sf.format(new Date());
                String fileName = "962200_IVRMYDXXYS_" + dir + ".xml";
                String pathname = System.getProperty("user.dir") + FILE_PATH + fileName;
                File file = new File(pathname);
                // 创建xml文件
                boolean isCreateFile = this.listToXml(list, file);
                ftpUploadFileLog.setFileName(fileName);
                ftpUploadFileLog.setFileType(FILE_TYPE_XML);
                ftpUploadFileLog.setFileSize(String.valueOf(file.length()));
                // 创建文件成功,上传文件
                if (isCreateFile) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    this.uploadFile(fileInputStream, fileName, null, ftpUploadFileLog);
                }
                ftpUploadFileLog.setIsCreateFile(isCreateFile);
                ftpUploadFileLog.setFileOriginPath(pathname);
            } else {
                log.info("queryZjRecordInfoList2:未查询到数据");
                ftpUploadFileLog.setUploadErrorMsg("queryZjRecordInfoList2:未查询到数据");
            }
            // ftp上传记录入库，记录是否上传成功，如果不成功就定时任务上传
            this.addFtpUploadFileLog(ftpUploadFileLog);
        } catch (Exception e) {
            log.info("taskForXmlZjRecordInfo2-ftp上传文件失败：{}", e.getMessage());
            ftpUploadFileLog.setUploadErrorMsg(e.getMessage().substring(0, 3000));
            this.addFtpUploadFileLog(ftpUploadFileLog);
        }
    }

    /**
     * 检查今天的ftp上传是否成功，没有成功，进行二次上传
     * @param createTimeStr
     */
    @Override
    public void checkUploadFile(String createTimeStr) {
        if (StringUtils.isBlank(createTimeStr)) {
            createTimeStr = DateUtils.getDate() + " 00:00:00";
        }
        LambdaQueryWrapper<FtpUploadFileLog> queryWrapper = new LambdaQueryWrapper<>();
        // 查询今天上传失败的记录
        queryWrapper.gt(FtpUploadFileLog::getCreateTime, createTimeStr)
                .eq(FtpUploadFileLog::getIsUpload, false)
                .eq(FtpUploadFileLog::getFileUse, 1L);
        List<FtpUploadFileLog> uploadFileLogList = ftpUploadFileLogMapper.selectList(queryWrapper);
        // 有上传失败的，重新上传
        if (!CollectionUtils.isEmpty(uploadFileLogList)) {
            for (FtpUploadFileLog fileLog : uploadFileLogList) {
                try {
                    FileInputStream fileInputStream = new FileInputStream(fileLog.getFileOriginPath());
                    // ftp再次上传文件
                    this.uploadFile(fileInputStream, fileLog.getFileName(), fileLog.getFileUploadPath(), fileLog);
                    fileLog.setUpdateTime(new Date());
                    ftpUploadFileLogMapper.updateById(fileLog);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                    log.info("ftp再次上传失败：{}", e.getMessage());
                }
            }
        }
    }

    /**
     * 定时删除三个月前的文件（本地服务器上的文件）
     * @param date
     * */
    @Override
    public void deleteOriginFile(Date date) {
        LambdaQueryWrapper<FtpUploadFileLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.lt(FtpUploadFileLog::getCreateTime, date)
                .eq(FtpUploadFileLog::getIsUpload, true)
                .eq(FtpUploadFileLog::getDelFlag, 0L);
        List<FtpUploadFileLog> uploadFileLogList = ftpUploadFileLogMapper.selectList(queryWrapper);
        // 有数据，就删除本地服务器上的文件
        if (!CollectionUtils.isEmpty(uploadFileLogList)) {
            for (FtpUploadFileLog fileLog : uploadFileLogList) {
                File file = new File(fileLog.getFileOriginPath());
                file.delete();
                fileLog.setDelFlag(1L);
                fileLog.setUpdateTime(new Date());
                ftpUploadFileLogMapper.updateById(fileLog);
            }
        }else {
            log.info("没有查询到本地文件");
        }


    }

    /**
     * ftp上传文件
     *
     * @param fileInputStream  文件流
     * @param fileName         文件名称
     * @param ftpPath          ftp上的文件目录路径
     * @param ftpUploadFileLog 上传文件日志
     *                         *
     */
    private void uploadFile(FileInputStream fileInputStream, String fileName, String ftpPath, FtpUploadFileLog ftpUploadFileLog) {
        try {
            // ftp上传文件
            String fileUploadPath = FTP2Tools.upload(fileInputStream, fileName, ftpPath);
            ftpUploadFileLog.setUploadTime(new Date());
            if (StringUtils.isNotBlank(fileUploadPath)) {
                ftpUploadFileLog.setIsUpload(true);
                ftpUploadFileLog.setFileUploadPath(fileUploadPath);
            } else {
                ftpUploadFileLog.setIsUpload(false);
            }
        }catch (Exception e) {
            log.error("上传文件失败：{}", e.getMessage());
        }finally {
            // 关闭文件流
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 创建xml文件, 把数据放到xml文件中
     *
     * @param list
     * @param file
     * @return
     */
    private boolean listToXml(List<Map<String, Object>> list, File file) {
        Document doc = this.paramUtil(list);
        OutputFormat format = OutputFormat.createPrettyPrint();
        // 之前的编码
//        format.setEncoding(ENCODING_GB2313);
        // 现在的编码
        format.setEncoding(ENCODING_UTF8);
        Writer writer = null;
        XMLWriter output = null;
        try {
            if (!file.exists()) {
                file.getParentFile().mkdirs();
            }
            file.createNewFile();
            writer = new FileWriter(file);
            output = new XMLWriter(writer, format);
            output.write(doc);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            log.info("ftp上传文件失败：{}", e.getMessage());
            return false;
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
                if (output != null) {
                    output.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 把数据转换成xml文件
     *
     * @param list
     * @return
     */
    private Document paramUtil(List<Map<String, Object>> list) {
        Document doc = null;
        try {
            doc = DocumentHelper.createDocument();
            Element root = doc.addElement("Request");
            for (Map<String, Object> map : list) {
                Element stuEle = root.addElement("information");
                for (Map.Entry<String, Object> m : map.entrySet()) {
                    Element nameEle = stuEle.addElement("param");
                    if ("null".equals(m.getValue()) || ObjectUtils.isEmpty(m.getValue())) {
                        nameEle.addAttribute("name", String.valueOf(m.getKey()));
                    } else {
                        nameEle.addAttribute("name", String.valueOf(m.getKey()));
                        nameEle.setText(String.valueOf(m.getValue()));
                    }
                }
            }
        } catch (Exception e) {
            log.info("数据转换成XML文件失败：{}", e.getMessage());
        }
        return doc;
    }

    /**
     * 添加ftp上传文件到大数据中心的日志
     * @param ftpUploadFileLog
     */
    private void addFtpUploadFileLog(FtpUploadFileLog ftpUploadFileLog) {
        if (ftpUploadFileLog == null) {
            log.info("ftpUploadFileLog是null");
            return;
        }
        log.info("ftpUploadFileLog: {}", ftpUploadFileLog.toString());
        // 单独线程添加操作日志
        new Thread(new Runnable() {
            @Override
            public void run() {
                ftpUploadFileLog.setCreateTime(new Date());
                ftpUploadFileLog.setUpdateTime(new Date());
                ftpUploadFileLog.setUploadTime(new Date());
                ftpUploadFileLog.setFileUse(1L);
                ftpUploadFileLogMapper.insert(ftpUploadFileLog);
            }
        }).start();

    }


}
